package com.aspect;

import com.annotation.UserAccess;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 因为Spring基于动态代理， 所以Spring只支持方法连接点。 这与
 * 一些其他的AOP框架是不同的， 例如AspectJ和JBoss， 除了方法切
 * 点， 它们还提供了字段和构造器接入点。
 * <p>
 * AspectJ指示器 描 述
 * arg() 限制连接点匹配参数为指定类型的执行方法    注：用于传递参数给切面方法
 * @args() 限制连接点匹配参数由指定注解标注的执行方法
 * execution() 用于匹配是连接点的执行方法
 * execution(public * com.dbgo..*.app.*.*(..)) 表示任意返回值类型 com.dbgo包下任意app子包下的任意方法，任意参数
 * this() 限制连接点匹配AOP代理的bean引用为指定类型的类
 * target 限制连接点匹配目标对象为指定类型的类
 * @target() 限制连接点匹配特定的执行对象， 这些对象对应的类要具有指定类型的注解
 * within() 限制连接点匹配指定的类型
 * @within() 限制连接点匹配指定注解所标注的类型（当使用Spring AOP时， 方法定义在由指定的注解所标注的类里）
 * @annotation 限定匹配带有指定注解的连接点
 *
 * 注意只有execution指示器是实际执行匹配的， 而其他的指示器都是用来限制匹配的。
 *
 * 通过切面还可以在不修改源码的情况下为对象增加新的功能、方法  使用@DeclareParents注解
 *
 */
@Aspect
@Component
public class ActionAspect {

	/*
	 * 第一种方法
	 */
	//定义切点
	@Pointcut("@annotation(com.annotation.UserAccess)")
	public void controllerAspect() {
	}

	@Around("controllerAspect()")
	public void doControllerAround(ProceedingJoinPoint point) throws Throwable {
		MethodSignature signature = (MethodSignature) point.getSignature();
		Method method = signature.getMethod();
		UserAccess annotation = method.getAnnotation(UserAccess.class);
//		Object target = point.getTarget();
//		UserAccess annotation1 = target.getClass().getAnnotation(UserAccess.class);
		String name = annotation.name();
	}

	/*或者这样写：不定义切点*/
//	@Around("@annotation(userAccess)")
//	public void doControllerAround(ProceedingJoinPoint point, UserAccess userAccess) throws Throwable {
//
//	}
}
